package gameCard

import (
	"common"
	"common/biz"
	"common/logs"
	"common/utils"
	"core/service"
	"encoding/json"
	"fmt"
	"framework/remote"
	"game/component/base"
	"game/component/proto"
	"game/models/request"
	"sync"
	"time"
)

const (
	UserWebTime = 2 * 60 //心跳(s)
)

type GameFrame struct {
	sync.RWMutex
	r              base.RoomFrame
	gameRule       request.GameRule
	gameData       *GameData
	logic          *Logic
	turnSchedule   *time.Timer
	usersHeartbeat map[uint]*time.Timer
	battleUsers    []int
	ch             chan ChHandler
}

func (g *GameFrame) GetGameData(session *remote.Session) any {
	return g.gameData
}

// StartGame 游戏开始处理
func (g *GameFrame) StartGame(session *remote.Session, warehouseService *service.WarehouseService) {
	//开始游戏
	//1.初始化人物属性
	for i := 0; i < g.gameData.ChairCount; i++ {
		g.gameData.Users[i] = g.initUser(i, session)
	}
	//2.扣除游戏币
	rid, ok := session.Get("roomId")
	if !ok {
		//房间ID不存在
		return
	}
	err := warehouseService.StarGame(g.GetAllUsersInt(), g.gameRule.BaseScore, fmt.Sprintf("%v", rid))
	if err != nil {
		//用户异常 验资不通过返回信息给用户 房间已解散
		g.sendData(GameErrorResponseData(common.F(biz.GameError)))
		g.r.DismissRoom()
		return
	}
	//3.游戏状态 初始状态 推送
	g.gameData.GameStarted = true
	g.gameData.GameStatus = Start
	logs.Warn("房间%v,游戏开始了,状态为%d", g.r.GetRoomID(), g.gameData.GameStatus)
	g.sendData(GameStatusPushData(g.gameData.GameStatus, g.gameRule.OperateSleep, 0))
	//整理牌
	go g.logic.handlerCards()
	g.ch <- ChHandler{GameStatus: Select}
}

// GameMessageHandle 游戏操作
func (g *GameFrame) GameMessageHandle(user *proto.RoomUser, session *remote.Session, msg []byte) {
	var req MessageReq
	_ = json.Unmarshal(msg, &req)
	if g.gameData.Users[user.ChairID].ChairID != user.ChairID || g.gameData.Users[user.ChairID].UID != user.UserInfo.UID {
		g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameNotUserInfoError)), session)
		return
	}
	//游戏结算状态
	if g.gameData.Users[user.ChairID].Status == UserStatusEnd {
		g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameUserStatusError)), session)
		return
	}
	//重置用户心跳
	g.Lock()
	defer g.Unlock()
	if g.usersHeartbeat[user.UserInfo.UID] != nil {
		g.usersHeartbeat[user.UserInfo.UID].Reset(UserWebTime * time.Second)
	} else {
		if g.gameData.Users[user.ChairID].IsHangUp {
			g.gameData.Users[user.ChairID].IsHangUp = false
			go g.checkUserHeartbeatTimer(user.ChairID, user.UserInfo.UID, session)
		}
	}
	//操作
	if req.Type == GameSendRefreshCardsPull { //购买卡牌
		if req.Data.Operate != OperateTypeBuy {
			logs.Error("[game]%d用户 购买卡牌操作,err=操作类型不同,req=%v", user.UserInfo.UID, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		if g.gameData.GameStatus != Select {
			logs.Error("[game]%d用户 购买卡牌操作,err=不是选牌页面不能操作,现在是状态%d,req=%v", user.UserInfo.UID, g.gameData.GameStatus, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		g.buyRefreshCards(req.Data, user.ChairID, session)
	} else if req.Type == GameSendRefreshPull { //刷新
		if req.Data.Operate != OperateTypeRefresh {
			logs.Error("[game]%d用户 刷新卡牌,err=操作类型不同,req=%v", user.UserInfo.UID, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		if g.gameData.GameStatus != Select {
			logs.Error("[game]%d用户 刷新卡牌,err=不是选牌页面不能操作,现在是状态%d,req=%v", user.UserInfo.UID, g.gameData.GameStatus, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		g.refreshCards(user.ChairID, session)
	} else if req.Type == GameUpgradePull { //升级
		if req.Data.Operate != OperateTypeUpgrade {
			logs.Error("[game]%d用户 升级角色,err=操作类型不同,req=%v", user.UserInfo.UID, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		if g.gameData.GameStatus != Select && g.gameData.GameStatus != Playing && g.gameData.GameStatus != Battle {
			logs.Error("[game]%d用户 升级角色,err=不是选牌页面和战斗页面不能操作,现在是状态%d,req=%v", user.UserInfo.UID, g.gameData.GameStatus, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		g.upgrade(user.ChairID, session)
	} else if req.Type == GameSkillPull { //购买技能
		if req.Data.Operate != OperateTypeSkill {
			logs.Error("[game]%d用户 购买技能,err=操作类型不同,req=%v", user.UserInfo.UID, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		if g.gameData.GameStatus != Select && g.gameData.GameStatus != Playing && g.gameData.GameStatus != Battle {
			logs.Error("[game]%d用户 购买技能,err=不是选牌页面和对战页面不能操作,req=%v", user.UserInfo.UID, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		g.buySkill(user.ChairID, session)
	} else if req.Type == GameSendHandCardsPull { //操作手牌
		if g.gameData.GameStatus != Select {
			logs.Error("[game]%d用户 操作手牌,err=不是选牌页面不能操作,现在是状态%d,req=%v", user.UserInfo.UID, g.gameData.GameStatus, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		if req.Data.Operate == OperateTypeSellCards { //出售手牌
			g.sellCard(req.Data, user.ChairID, session)
		} else if req.Data.Operate == OperateTypeInstallCard { //安装怪兽卡
			g.installCard(req.Data, user.ChairID, session)
		} else if req.Data.Operate == OperateTypeEvolutionCard { //吞噬卡
			g.evolutionCard(req.Data, user.ChairID, session)
		} else if req.Data.Operate == OperateTypeUpgradeCard { //升级卡
			g.upgradeCard(req.Data, user.ChairID, session)
		} else if req.Data.Operate == OperateTypeInstallEquipCard { //装备卡
			g.installEquipCard(req.Data, user.ChairID, session)
		} else {
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
	} else if req.Type == GameSendRSiteCardsPull { //操作场地牌
		if g.gameData.GameStatus != Select {
			logs.Error("[game]%d用户 操作场地牌,err=不是选牌页面不能操作,现在是状态%d,req=%v", user.UserInfo.UID, g.gameData.GameStatus, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		if req.Data.Operate == OperateTypeSellCards { //出售场地牌
			g.sellCard(req.Data, user.ChairID, session)
		} else {
			logs.Error("[game]%d用户 操作场地牌以外其它操作,err=传参错误,req=%v", user.UserInfo.UID, req)
			g.sendDataUsers([]string{fmt.Sprintf("%d", user.UserInfo.UID)}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}

	}
}

// sendHandle 轮回游戏开始处理
func (g *GameFrame) sendHandle() {
	//4.当前局数推送+1
	g.gameData.CurBureau++
	g.sendData(GameBureauPushData(g.gameData.CurBureau))
	logs.Warn("房间%v,第%d回合开始", g.r.GetRoomID(), g.gameData.CurBureau)
	//排除第一回合 添加金币
	if g.gameData.CurBureau > 1 {
		for chairID, user := range g.gameData.Users {
			if user.Status == UserStatusEnd {
				continue
			}
			gold := int64(g.gameData.CurBureau-1) + g.gameRule.InitGold
			if gold > g.gameRule.GoldMax {
				gold = g.gameRule.GoldMax
			}
			//uidStr := fmt.Sprint(user.UID)
			//人物技能
			if user.IsSkill {
				if user.SkillType == Gold { //获得金币
					gold += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
					g.sendDataUsersInt([]int{user.ChairID}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc))
				} else if user.SkillType == Blood && user.Blood < g.gameRule.InitBlood { //回血
					blood := g.getUserByChairID(chairID).UserInfo.RoleSkillVal
					if user.Blood+g.getUserByChairID(chairID).UserInfo.RoleSkillVal > g.gameRule.InitBlood {
						blood = g.gameRule.InitBlood - user.Blood
					}
					user.Blood += blood
					g.sendDataUsersInt([]int{user.ChairID}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc))
				}
			}
			//每回合赠送金币
			//fmt.Println("当前局数", g.gameData.CurBureau, "用户ID", user.UID, "获得金币", gold)
			user.Gold += gold
			g.sendDataUsersInt([]int{user.ChairID}, GameGoldPushData(gold))
			//每回合赠送经验
			if user.Level < g.gameRule.LevelMax {
				user.NextLevelGold--
				if user.NextLevelGold == 0 {
					user.Level++
					//人物技能
					if user.IsSkill && SkillType(g.getUserByChairID(chairID).UserInfo.RoleSkillType) == ObtainCard && user.Level == int64(g.getUserByChairID(chairID).UserInfo.RoleSkillLevel) {
						//技能类型为获得卡牌
						g.sendDataUsersInt([]int{user.ChairID}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc))
						//发送赠送卡牌
						card := g.logic.getRefreshCards(int64(g.getUserByChairID(chairID).UserInfo.RoleSkillLinkCardType), 1)
						user.HandCards = append(user.HandCards, card[0].Card)
						g.sendDataUsersInt([]int{user.ChairID}, GameSendHandCardsPushData(user.HandCards))
					}
					if user.Level == g.gameRule.LevelMax {
						user.NextLevelGold = 0
						user.NextLevelGoldTotal = 0
					} else {
						user.NextLevelGold = (user.Level + 1) * g.gameRule.EachLevelGoldRate
						user.NextLevelGoldTotal = user.NextLevelGold
					}
				}
				g.sendDataUsersInt([]int{user.ChairID}, GameUpgradePushData(user.Level, user.NextLevelGold, user.NextLevelGoldTotal))
			}
			g.gameData.Users[chairID] = user
		}
	}
	//5.推送用户信息
	g.sendData(GameUserPushData(g.gameData.Users))
	var timer *time.Timer
	timer = time.AfterFunc(g.gameRule.OperateSleep*time.Second, func() {
		timer.Stop()
		//游戏正式开始处理
		//游戏状态 选牌 推送
		g.gameData.GameStatus = Select
		logs.Warn("房间%v,现在是选牌阶段,状态为%d", g.r.GetRoomID(), g.gameData.GameStatus)
		g.sendData(GameStatusPushData(g.gameData.GameStatus, g.gameRule.SelectCardSleep, 0))
		// 整理牌 再发刷新牌
		for i := 0; i < g.gameData.ChairCount; i++ {
			if g.gameData.Users[i].Status == UserStatusEnd {
				continue
			}
			g.gameData.Users[i].Refresh = g.logic.getRefreshCards(g.gameData.Users[i].Level, int(g.gameRule.RefreshCard))
			uid := fmt.Sprintf("%d", g.gameData.Users[i].UID)
			data := g.gameData.Users[i].Refresh
			logs.Warn("[game]用户%v,发放的刷新牌Refresh=%v\n,手牌为HandCards=%v\n,场地牌SiteCards=%v", uid, data, g.gameData.Users[i].HandCards, g.gameData.Users[i].SiteCards)
			g.sendDataUsersInt([]int{g.gameData.Users[i].ChairID}, GameSendRefreshCardsPushData(data))
		}
		//定时关闭刷新牌
		go g.turnScheduleExecute()
	})
}

func (g *GameFrame) sendDataUsersInt(ChairIDs []int, data any) {
	for _, v := range ChairIDs {
		user := g.gameData.Users[v]
		if user.UID != 0 {
			uidStr := []string{fmt.Sprintf("%d", user.UID)}
			g.ServerMessagePush(uidStr, data, user.Session)
		}
	}
}

func (g *GameFrame) sendDataUsers(users []string, data any, session *remote.Session) {
	g.ServerMessagePush(users, data, session)
}

func (g *GameFrame) sendData(data any) {
	for _, v := range g.gameData.Users {
		if v.Status == UserStatusEnd {
			continue
		}
		uidStr := []string{fmt.Sprintf("%d", v.UID)}
		g.ServerMessagePush(uidStr, data, v.Session)
	}
}

func (g *GameFrame) ServerMessagePush(users []string, data any, session *remote.Session) {
	session.Push(users, data, "ServerMessagePush")
}

func (g *GameFrame) GetAllUsersStr() []string {
	users := make([]string, 0)
	for _, v := range g.r.GetUsers() {
		if v.UserStatus == proto.Dismiss {
			continue
		}
		users = append(users, fmt.Sprintf("%d", v.UserInfo.UID))
	}
	return users
}

func (g *GameFrame) GetAllUsersInt() []uint {
	users := make([]uint, 0)
	for _, v := range g.r.GetUsers() {
		users = append(users, v.UserInfo.UID)
	}
	return users
}

func (g *GameFrame) getUserByChairID(chairID int) *proto.RoomUser {
	for _, v := range g.r.GetUsers() {
		if v.ChairID == chairID {
			return v
		}
	}
	return nil
}

func (g *GameFrame) initBattleUser() {
	g.battleUsers = make([]int, 0)
	for _, v := range g.gameData.Users {
		if v.Status == UserStatusEnd {
			continue
		}
		if v.Opponent != -2 {
			continue
		}
		g.battleUsers = append(g.battleUsers, v.ChairID)
	}
}

// turnScheduleExecute 定时处理刷新牌回归卡组安排对战
func (g *GameFrame) turnScheduleExecute() {
	if g.turnSchedule != nil {
		g.turnSchedule.Stop()
	}
	g.turnSchedule = time.AfterFunc(time.Second*g.gameRule.SelectCardSleep, func() {
		// 取消定时
		if g.turnSchedule != nil {
			g.turnSchedule.Stop()
		}
		if g.gameData.GameStatus == Result {
			return
		}
		//通知用户刷新牌为空
		g.refreshCardKill()
		//初始化对战用户
		g.initBattleUser()
		//分配对战
		g.ch <- ChHandler{
			GameStatus: Playing,
		}
	})
}

// refreshCardKill 刷新牌回归卡组
func (g *GameFrame) refreshCardKill() {
	for chairID, v := range g.gameData.Users {
		if g.gameData.Users[chairID].Status == UserStatusEnd {
			continue
		}
		//回退刷新牌到牌库
		g.logic.cardsReturn(v.Refresh)
		//抹去用户的刷新牌库
		g.gameData.Users[chairID].Refresh = make([]RefreshCard, g.gameRule.RefreshCard)
		g.gameData.Users[chairID].Refresh = make([]RefreshCard, 0)
		g.sendDataUsersInt([]int{chairID}, GameSendRefreshCardsPushData(g.gameData.Users[chairID].Refresh))
	}
	//洗牌
	g.logic.washCards()
}

// distributionBattle 分配对战
func (g *GameFrame) distributionBattle() {
	//游戏状态 分配对战 推送
	g.gameData.GameStatus = Playing
	logs.Warn("房间%v,现在是对战加载中,状态为%d", g.r.GetRoomID(), g.gameData.GameStatus)
	g.sendData(GameStatusPushData(g.gameData.GameStatus, g.gameRule.OperateSleep, 0))
	//分配对手
	total := g.gameInCount(1)
	battleLayouts := make([]BattleLayout, 0)
	for chairID, v := range g.gameData.Users {
		//本人已结算退出
		if v.Status == UserStatusEnd {
			continue
		}
		//本人已被安排对战了
		if g.gameData.Users[chairID].Opponent != -2 {
			g.sendDataUsersInt([]int{chairID}, GameBattlePushData(v.Opponent, g.gameData.Users[g.gameData.Users[chairID].Opponent]))
			continue
		}
		var opponent int
		var wg sync.WaitGroup
		wg.Add(1)
		// 异常时用户只有1个了那么轮空
		go func() {
			for {
				rands := utils.Random(1, g.gameData.ChairCount)
				rands--
				opponent = int(rands)
				// TODO 如果定时器在这时清退了用户 那么这里可能陷入死循环
				total = g.gameInCount(1)
				if total < 2 {
					opponent = -1
					wg.Done()
					break
				}
				if g.gameData.Users[opponent].Status == UserStatusEnd {
					continue
				}
				if opponent == chairID {
					continue
				}
				if g.gameData.Users[opponent].Opponent == -2 {
					wg.Done()
					break
				}
			}
		}()
		wg.Wait()
		//轮空玩家 或 异常时用户只有1个了那么轮空
		if total < 2 || opponent == -1 {
			g.gameData.Users[chairID].Opponent = -1
			g.sendDataUsersInt([]int{chairID}, GameBattlePushData(-1, Users{}))
			one := BattleUser{
				UID:      v.UID,
				ChairID:  chairID,
				Status:   1,
				Monsters: v.SiteCards,
			}
			battleLayouts = append(battleLayouts, BattleLayout{
				One:    one,
				Status: true,
			})
			continue
		}

		g.gameData.Users[chairID].Opponent = opponent
		g.gameData.Users[opponent].Opponent = chairID
		one := BattleUser{
			UID:      v.UID,
			ChairID:  chairID,
			Status:   0,
			Monsters: make([]MonstersCard, len(v.SiteCards)),
		}
		copy(one.Monsters, v.SiteCards)
		two := BattleUser{
			UID:      g.gameData.Users[opponent].UID,
			ChairID:  opponent,
			Status:   0,
			Monsters: make([]MonstersCard, len(g.gameData.Users[opponent].SiteCards)),
		}
		copy(two.Monsters, g.gameData.Users[opponent].SiteCards)
		layout := BattleLayout{
			One: one,
			Two: two,
		}
		battleLayouts = append(battleLayouts, layout)
		total -= 2
		g.sendDataUsersInt([]int{chairID}, GameBattlePushData(opponent, g.gameData.Users[opponent]))
	}
	var timer *time.Timer
	timer = time.AfterFunc(time.Second*g.gameRule.OperateSleep, func() {
		// 取消定时
		timer.Stop()
		// TODO 战斗
		g.ch <- ChHandler{
			GameStatus: Battle,
			Battle:     &battleLayouts,
		}
	})
}

func (g *GameFrame) gameInCount(types int) int {
	var count int
	for _, v := range g.gameData.Users {
		if v.Status == UserStatusEnd {
			continue
		}
		if types == 1 {
			if v.Opponent == -2 {
				count++
			}
		} else {
			count++
		}
	}
	return count
}

// buyRefreshCards 购买刷新牌
func (g *GameFrame) buyRefreshCards(req MessageData, chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	//手牌超出
	if len(user.HandCards) >= int(g.gameRule.HandCardMaxNum) {
		logs.Error("[game]%d用户 购买卡牌操作,err=手牌超出,req=%v", user.UID, user.HandCards)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameHandCardMaxNumError)), session)
		return
	}
	if len(user.Refresh) < req.CardKey+1 {
		logs.Error("[game]%d用户 购买卡牌操作,err=传参下标超过刷新牌的总量,Refresh=%v,req=%v", user.UID, user.Refresh, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	//刷新卡已购买
	if user.Refresh[req.CardKey].IsBuy {
		logs.Error("[game]%d用户 购买卡牌操作,err=该卡牌已购买,Refresh=%v,req=%v", user.UID, user.Refresh, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameBuyRepeatError)), session)
		return
	}
	if user.Refresh[req.CardKey].Card.CardID != req.CardID || user.Refresh[req.CardKey].Card.CardIDTypeID != req.CardIDTypeID {
		logs.Error("[game]%d用户 购买卡牌操作,err=刷新牌池无这张牌传参错误,Refresh=%v,req=%v", user.UID, user.Refresh, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	//金币不足
	if user.Gold < user.Refresh[req.CardKey].Card.Price {
		logs.Error("[game]%d用户 购买卡牌操作,err=金币不足,Refresh=%v,req=%v", user.UID, user.Gold, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameGoldNotEnoughError)), session)
		return
	}
	//扣除金币
	gold := user.Refresh[req.CardKey].Card.Price
	//人物技能
	if user.IsSkill && SkillType(g.getUserByChairID(chairID).UserInfo.RoleSkillType) == AuxiliaryCardCardSubGold && CardType(g.getUserByChairID(chairID).UserInfo.RoleSkillNotCardType) != user.Refresh[req.CardKey].Card.CardType {
		//辅助卡减金
		g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
		gold += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
	}
	user.Gold -= gold
	g.sendDataUsers([]string{uidStr}, GameGoldPushData(user.Gold), session)
	//将刷新牌组的卡牌更改为已购买
	user.Refresh[req.CardKey].IsBuy = true
	//移除刷新牌
	//user.Refresh = append(user.Refresh[:req.CardKey], user.Refresh[req.CardKey+1:]...)
	//添加到手牌
	user.HandCards = append(user.HandCards, user.Refresh[req.CardKey].Card)
	g.sendDataUsers([]string{uidStr}, GameSendRefreshCardsPushData(user.Refresh), session)
	g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	g.gameData.Users[chairID] = user
}

// refreshCards 刷新
func (g *GameFrame) refreshCards(chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	//金币不足
	if user.Gold < g.gameRule.RefreshGold {
		logs.Error("[game]%d用户 刷新卡牌,err=金币不足,req=%v", user.UID, user)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameGoldNotEnoughError)), session)
		return
	}
	//扣除金币
	gold := g.gameRule.RefreshGold
	//人物技能
	if user.IsSkill && SkillType(g.getUserByChairID(chairID).UserInfo.RoleSkillType) == Refresh && user.SkillRefreshVal > 0 {
		//刷新免费
		gold = 0
		user.SkillRefreshVal--
		//使用技能
		g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
	}
	user.Gold -= gold
	g.sendDataUsers([]string{uidStr}, GameGoldPushData(user.Gold), session)
	//退还刷新牌
	g.logic.cardsReturn(user.Refresh)
	//重置刷新牌
	user.Refresh = make([]RefreshCard, g.gameRule.RefreshCard)
	//发牌
	user.Refresh = g.logic.getRefreshCards(user.Level, int(g.gameRule.RefreshCard))
	g.sendDataUsers([]string{uidStr}, GameSendRefreshCardsPushData(user.Refresh), session)
	g.gameData.Users[chairID] = user
}

// upgrade 升级角色
func (g *GameFrame) upgrade(chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if user.Level >= g.gameRule.LevelMax {
		logs.Error("[game]%d用户 升级角色,err=已到达等级上线，req=%v", user.UID, user.Level)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameLevelMaxError)), session)
		return
	}
	if user.Gold < 1 {
		logs.Error("[game]%d用户 升级角色,err=金币不足,req=%v", user.UID, user.Level)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameGoldNotEnoughError)), session)
		return
	}
	user.Gold--
	g.sendDataUsers([]string{uidStr}, GameGoldPushData(user.Gold), session)
	user.NextLevelGold--
	if user.NextLevelGold == 0 {
		user.Level++
		//人物技能
		if user.IsSkill && SkillType(g.getUserByChairID(chairID).UserInfo.RoleSkillType) == ObtainCard && user.Level == int64(g.getUserByChairID(chairID).UserInfo.RoleSkillLevel) {
			//技能类型为获得卡牌
			g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
			//发送赠送卡牌
			card := g.logic.getRefreshCards(int64(g.getUserByChairID(chairID).UserInfo.RoleSkillLinkCardType), 1)
			user.HandCards = append(user.HandCards, card[0].Card)
			g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
		}
		if user.Level == g.gameRule.LevelMax {
			user.NextLevelGold = 0
			user.NextLevelGoldTotal = 0
		} else {
			user.NextLevelGold = (user.Level + 1) * g.gameRule.EachLevelGoldRate
			user.NextLevelGoldTotal = user.NextLevelGold
		}
	}
	g.sendDataUsers([]string{uidStr}, GameUpgradePushData(user.Level, user.NextLevelGold, user.NextLevelGoldTotal), session)
	g.gameData.Users[chairID] = user
}

// buySkill 购买技能
func (g *GameFrame) buySkill(chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if user.Level < g.gameRule.ConditionBuySkillLevel {
		logs.Error("[game]%d用户 购买技能,err=未到达能购买技能的等级,我的等级%d,条件等级%d", user.UID, user.Level, g.gameRule.ConditionBuySkillLevel)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameConditionBuySkillLevelError)), session)
		return
	}
	if user.Gold < user.SkillPrice {
		logs.Error("[game]%d用户 购买技能,err=金币不足,我的金币%d,条件金币%d", user.UID, user.Gold, user.SkillPrice)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameGoldNotEnoughError)), session)
		return
	}
	if user.IsSkill {
		logs.Error("[game]%d用户 购买技能,err=已购买技能", user.UID)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameSkillBuyRepeatError)), session)
		return
	}
	user.Gold -= user.SkillPrice
	g.sendDataUsers([]string{uidStr}, GameGoldPushData(user.Gold), session)
	user.IsSkill = true
	//购买技能
	g.sendDataUsers([]string{uidStr}, GameSkillPushData(1, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
	//人物技能
	if user.SkillType == Attack {
		//增加攻击力
		for k, v := range user.SiteCards {
			v.AdditionalAttack += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			v.TotalAttack += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			user.SiteCards[k] = v
		}
		g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
	} else if user.SkillType == Defense {
		//增加血量
		for k, v := range user.SiteCards {
			v.AdditionalBlood += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			v.TotalBlood += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			v.SurplusBlood += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			user.SiteCards[k] = v
		}
		g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
	} else if user.SkillType == ObtainCard && user.Level == int64(g.getUserByChairID(chairID).UserInfo.RoleSkillLevel) {
		//技能类型为获得卡牌
		g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
		//发送赠送卡牌
		card := g.logic.getRefreshCards(int64(g.getUserByChairID(chairID).UserInfo.RoleSkillLinkCardType), 1)
		user.HandCards = append(user.HandCards, card[0].Card)
		g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	}
	g.gameData.Users[chairID] = user
}

// sellCard 出售卡牌
func (g *GameFrame) sellCard(req MessageData, chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if req.Type != -1 {
		logs.Error("[game]%d用户 操作手牌-出售,err=传参类型错误,req=%v", user.UID, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if req.Source == 1 {
		if len(user.HandCards) < req.CardKey+1 {
			logs.Error("[game]%d用户 操作手牌-出售,err=传参下标超过手牌的总量,HandCards=%v,req=%v", user.UID, user.HandCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		//手牌
		if user.HandCards[req.CardKey].CardID != req.CardID || user.HandCards[req.CardKey].CardIDTypeID != req.CardIDTypeID {
			logs.Error("[game]%d用户 操作手牌-出售,err=在手牌上未找到卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
			return
		}
		price := user.HandCards[req.CardKey].Price
		// TODO 大胡子 那维莱特 BUG 购买金币-1 出售未扣金币 原价出售
		//if user.IsSkill && user.SkillType == AuxiliaryCardCardSubGold && user.HandCards[req.CardKey].CardType == Ordinary {
		//	price += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
		//}
		//添加金币
		user.Gold += price
		g.sendDataUsers([]string{uidStr}, GameGoldPushData(user.Gold), session)
		//退还手牌
		g.logic.retreatHandCard(user.HandCards[req.CardKey])
		//删除手牌
		user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
		g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	} else {
		if len(user.SiteCards) < req.CardKey+1 {
			logs.Error("[game]%d用户 操作场地牌-出售,err=传参下标超过场地牌的总量,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		//场地牌
		if user.SiteCards[req.CardKey].CardID != req.CardID || user.SiteCards[req.CardKey].CardIDTypeID != req.CardIDTypeID {
			logs.Error("[game]%d用户 操作场地牌-出售,err=在场地牌上未找到卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
			return
		}
		//添加金币
		user.Gold += int64(float64(user.SiteCards[req.CardKey].TotalPrice) * g.gameRule.CardSecondHandPrice)
		g.sendDataUsers([]string{uidStr}, GameGoldPushData(user.Gold), session)
		//退还场地牌
		g.logic.retreatSiteCard(user.SiteCards[req.CardKey])
		//删除场地牌
		user.SiteCards = append(user.SiteCards[:req.CardKey], user.SiteCards[req.CardKey+1:]...)
		g.sendDataUsers([]string{uidStr}, GameSendSiteCardsPushData(user.SiteCards), session)
	}
	g.gameData.Users[chairID] = user
}

// installCard 安装卡牌
func (g *GameFrame) installCard(req MessageData, chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if req.Type != 1 || req.Source != 1 {
		logs.Error("[game]%d用户 操作手牌-安装怪兽卡,err=不是安装怪兽卡或不是手牌,req=%v", user.UID, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if len(user.HandCards) < req.CardKey+1 {
		logs.Error("[game]%d用户 操作手牌-安装怪兽卡,err=传参下标超过手牌的总量,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if user.HandCards[req.CardKey].CardID != req.CardID || user.HandCards[req.CardKey].CardIDTypeID != req.CardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-安装怪兽卡,err=在手牌上未找到卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	if user.HandCards[req.CardKey].CardType != Ordinary {
		logs.Error("[game]%d用户 操作手牌-安装怪兽卡,err=操作的卡牌不是怪兽卡,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	monstersCard := MonstersCard{
		Card:       user.HandCards[req.CardKey],
		TotalPrice: user.HandCards[req.CardKey].Price,
		Arms:       Card{},
		Defense:    Card{},
		UpCard:     make([]Card, 0),
	}
	//人物技能
	if user.IsSkill {
		if user.SkillType == Attack {
			//增加攻击力
			monstersCard.AdditionalAttack += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			monstersCard.TotalAttack += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
		} else if user.SkillType == Defense {
			//增加血量
			monstersCard.AdditionalBlood += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			monstersCard.TotalBlood += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			monstersCard.SurplusBlood += g.getUserByChairID(chairID).UserInfo.RoleSkillVal
			g.sendDataUsers([]string{uidStr}, GameSkillPushData(2, g.getUserByChairID(chairID).UserInfo.RoleSkillDesc), session)
		}
	}
	user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
	g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	user.SiteCards = append(user.SiteCards, monstersCard)
	g.sendDataUsers([]string{uidStr}, GameSendSiteCardsPushData(user.SiteCards), session)
	g.gameData.Users[chairID] = user
}

// evolutionCard 吞噬卡牌
func (g *GameFrame) evolutionCard(req MessageData, chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if req.Type != 2 {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=不是吞噬卡牌,req=%v", user.UID, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if len(user.HandCards) < req.CardKey+1 {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=传参下标超过手牌的总量,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	//手牌
	if user.HandCards[req.CardKey].CardID != req.CardID || user.HandCards[req.CardKey].CardIDTypeID != req.CardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=在手牌上未找到卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	//手牌不是吞噬卡
	if user.HandCards[req.CardKey].CardType != Evolution {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=不是吞噬卡,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if len(user.SiteCards) < req.JustCardKey+1 {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=传参下标超过场地牌的总量,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	//牌1
	if user.SiteCards[req.JustCardKey].CardID != req.JustCardID || user.SiteCards[req.JustCardKey].CardIDTypeID != req.JustCardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=在场地牌上未找到卡牌,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	//已升星
	if user.SiteCards[req.JustCardKey].Star > 0 {
		logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=该卡牌已吞噬过,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameRisingStarError)), session)
		return
	}
	if req.DeputySource == 1 { //副卡为手牌
		if len(user.HandCards) < req.DeputyCardKey+1 {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡-传参下标超过手牌的总量,HandCards=%v,req=%v", user.UID, user.HandCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		//两只怪兽卡不同无法升级
		if user.SiteCards[req.JustCardKey].CardID != user.HandCards[req.DeputyCardKey].CardID {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为手牌-两种卡牌不是同一类型,HandCards=%v,SiteCards=%v,req=%v", user.UID, user.HandCards, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardNotError)), session)
			return
		}
		//两只怪兽卡不为怪兽卡
		if user.SiteCards[req.JustCardKey].CardType != Ordinary || user.HandCards[req.DeputyCardKey].CardType != Ordinary {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为手牌-两种卡牌不是怪兽卡,HandCards=%v,SiteCards=%v,req=%v", user.UID, user.HandCards, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		//牌2
		if user.HandCards[req.DeputyCardKey].CardID != req.DeputyCardID || user.HandCards[req.DeputyCardKey].CardIDTypeID != req.DeputyCardIDTypeID {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为手牌-未找到副卡,HandCards=%v,req=%v", user.UID, user.HandCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
			return
		}
		//已升星
		if user.HandCards[req.DeputyCardKey].Star > 0 {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为手牌-已升星,HandCards=%v,req=%v", user.UID, user.HandCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameRisingStarError)), session)
			return
		}
		user.SiteCards[req.JustCardKey].Evolution.Monsters = user.HandCards[req.DeputyCardKey]
		//加战力 血量 潜力
		user.SiteCards[req.JustCardKey].Attack += user.HandCards[req.DeputyCardKey].Attack
		user.SiteCards[req.JustCardKey].TotalAttack += user.HandCards[req.DeputyCardKey].Attack
		user.SiteCards[req.JustCardKey].Blood += user.HandCards[req.DeputyCardKey].Blood
		user.SiteCards[req.JustCardKey].TotalBlood += user.HandCards[req.DeputyCardKey].Blood
		user.SiteCards[req.JustCardKey].SurplusBlood = user.SiteCards[req.JustCardKey].TotalBlood
		user.SiteCards[req.JustCardKey].Potential += user.HandCards[req.DeputyCardKey].Potential
		user.SiteCards[req.JustCardKey].TotalPotential += user.HandCards[req.DeputyCardKey].Potential
		user.SiteCards[req.JustCardKey].Star = 1

		user.SiteCards[req.JustCardKey].Evolution.Upgrade = user.HandCards[req.CardKey]
		if req.DeputyCardKey < req.CardKey {
			req.CardKey--
		}
		user.HandCards = append(user.HandCards[:req.DeputyCardKey], user.HandCards[req.DeputyCardKey+1:]...)
		user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
	} else { //副卡为场地牌
		if len(user.SiteCards) < req.DeputyCardKey+1 {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡-传参下标超过场地牌的总量,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		//两只怪兽卡不同无法升级
		if user.SiteCards[req.JustCardKey].CardID != user.SiteCards[req.DeputyCardKey].CardID {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为场地牌-两种卡牌不是同一类型,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardNotError)), session)
			return
		}
		//两只怪兽卡不为怪兽卡
		if user.SiteCards[req.JustCardKey].CardType != Ordinary || user.SiteCards[req.DeputyCardKey].CardType != Ordinary {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为场地牌-两种卡牌不是怪兽卡,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
			return
		}
		//牌2
		if user.SiteCards[req.DeputyCardKey].CardID != req.DeputyCardID || user.SiteCards[req.DeputyCardKey].CardIDTypeID != req.DeputyCardIDTypeID {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为场地牌-未找到副卡,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
			return
		}
		//已升星
		if user.SiteCards[req.DeputyCardKey].Star > 0 {
			logs.Error("[game]%d用户 操作手牌-吞噬卡牌,err=副卡为场地牌-已升星,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameRisingStarError)), session)
			return
		}
		user.SiteCards[req.JustCardKey].Evolution.Monsters = user.SiteCards[req.DeputyCardKey].Card
		//加战力 血量 潜力
		user.SiteCards[req.JustCardKey].Attack += user.SiteCards[req.DeputyCardKey].Attack
		user.SiteCards[req.JustCardKey].TotalAttack += user.SiteCards[req.DeputyCardKey].Attack
		user.SiteCards[req.JustCardKey].Blood += user.SiteCards[req.DeputyCardKey].Blood
		user.SiteCards[req.JustCardKey].TotalBlood += user.SiteCards[req.DeputyCardKey].Blood
		user.SiteCards[req.JustCardKey].SurplusBlood = user.SiteCards[req.JustCardKey].TotalBlood
		user.SiteCards[req.JustCardKey].Potential += user.SiteCards[req.DeputyCardKey].Potential
		user.SiteCards[req.JustCardKey].TotalPotential += user.SiteCards[req.DeputyCardKey].Potential
		user.SiteCards[req.JustCardKey].Star = 1

		for _, v := range user.SiteCards[req.JustCardKey].UpCard {
			user.SiteCards[req.JustCardKey].Evolution.UpCard = append(user.SiteCards[req.JustCardKey].Evolution.UpCard, v)
		}
		user.SiteCards[req.JustCardKey].Evolution.Upgrade = user.HandCards[req.CardKey]
		user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
		user.SiteCards = append(user.SiteCards[:req.DeputyCardKey], user.SiteCards[req.DeputyCardKey+1:]...)
	}
	g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	g.sendDataUsers([]string{uidStr}, GameSendSiteCardsPushData(user.SiteCards), session)
	g.gameData.Users[chairID] = user
}

// upgradeCard 升级怪兽
func (g *GameFrame) upgradeCard(req MessageData, chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if req.Type != 3 {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=不是升级怪兽,req=%v", user.UID, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if len(user.HandCards) < req.CardKey+1 {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=传参下标超过手牌的总量,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if user.HandCards[req.CardKey].CardID != req.CardID || user.HandCards[req.CardKey].CardIDTypeID != req.CardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=手牌未获取到改卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	if req.Source != 2 {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=操作不是给场地牌,req=%v", user.UID, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	//手牌不是升级卡
	if user.HandCards[req.CardKey].CardType != Upgrade {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=不是升级卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if len(user.SiteCards) < req.JustCardKey+1 {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=传参下标超过场地牌的总量,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if user.SiteCards[req.JustCardKey].CardID != req.JustCardID || user.SiteCards[req.JustCardKey].CardIDTypeID != req.JustCardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=在场地牌上未获取到该卡排,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	//未升星无法升级
	if user.SiteCards[req.JustCardKey].Star != 1 {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=场地牌未升星不能升级,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameNotUpgradeStarError)), session)
		return
	}
	//等级已达到上限
	if user.SiteCards[req.JustCardKey].Level >= g.gameRule.LevelMax {
		logs.Error("[game]%d用户 操作手牌-升级怪兽,err=已到达升级上限,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameLevelMaxError)), session)
		return
	}
	//添加 攻击 血量
	potentialRate := utils.Random(1, int(user.SiteCards[req.JustCardKey].TotalPotential))
	attack := user.SiteCards[req.JustCardKey].Attack * potentialRate
	blood := user.SiteCards[req.JustCardKey].Blood * potentialRate
	user.SiteCards[req.JustCardKey].AdditionalAttack += attack
	user.SiteCards[req.JustCardKey].TotalAttack += attack
	user.SiteCards[req.JustCardKey].AdditionalBlood += blood
	user.SiteCards[req.JustCardKey].TotalBlood += blood
	user.SiteCards[req.JustCardKey].SurplusBlood = user.SiteCards[req.JustCardKey].TotalBlood

	user.SiteCards[req.JustCardKey].Level++
	user.SiteCards[req.JustCardKey].UpCard = append(user.SiteCards[req.JustCardKey].UpCard, user.HandCards[req.CardKey])
	user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
	g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	g.sendDataUsers([]string{uidStr}, GameSendSiteCardsPushData(user.SiteCards), session)
	g.gameData.Users[chairID] = user
}

// installEquipCard 安装装备牌
func (g *GameFrame) installEquipCard(req MessageData, chairID int, session *remote.Session) {
	user := g.gameData.Users[chairID]
	uidStr := fmt.Sprintf("%d", user.UID)
	if req.Type != 4 {
		logs.Error("[game]%d用户 操作手牌-安装装备牌,err=不是安装装备牌,req=%v", user.UID, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if len(user.HandCards) < req.CardKey+1 {
		logs.Error("[game]%d用户 操作手牌-安装装备牌,err=传参下标超过手牌的总量,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if user.HandCards[req.CardKey].CardID != req.CardID || user.HandCards[req.CardKey].CardIDTypeID != req.CardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-安装装备牌,err=未获取到卡牌,HandCards=%v,req=%v", user.UID, user.HandCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	if len(user.SiteCards) < req.JustCardKey+1 {
		logs.Error("[game]%d用户 操作手牌-安装装备牌,err=传参下标超过场地牌的总量,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	if user.SiteCards[req.JustCardKey].CardID != req.JustCardID || user.SiteCards[req.JustCardKey].CardIDTypeID != req.JustCardIDTypeID {
		logs.Error("[game]%d用户 操作手牌-安装装备牌,err=未获取到场地牌,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameCardSelectError)), session)
		return
	}
	//未吞噬不能安装装备牌
	if user.SiteCards[req.JustCardKey].Star != 1 {
		logs.Error("[game]%d用户 操作手牌-安装装备牌,err=场地牌未升星不能升级,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameNotEvolutionError)), session)
		return
	}
	if user.HandCards[req.CardKey].CardType == Armour { //防具
		if user.SiteCards[req.JustCardKey].Defense.CardID != 0 {
			logs.Error("[game]%d用户 操作手牌-安装装备牌,err=该卡牌已安装防具,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameInstallEquipCardError)), session)
			return
		}
		//添加防具
		user.SiteCards[req.JustCardKey].Defense = user.HandCards[req.CardKey]
		user.SiteCards[req.JustCardKey].AdditionalBlood += user.HandCards[req.CardKey].Blood
		user.SiteCards[req.JustCardKey].TotalBlood += user.HandCards[req.CardKey].Blood
		user.SiteCards[req.JustCardKey].SurplusBlood = user.SiteCards[req.JustCardKey].TotalBlood
		user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
	} else if user.HandCards[req.CardKey].CardType == Weapon { //武器
		if user.SiteCards[req.JustCardKey].Arms.CardID != 0 {
			logs.Error("[game]%d用户 操作手牌-安装装备牌,err=该卡牌已安装武器,SiteCards=%v,req=%v", user.UID, user.SiteCards, req)
			g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameInstallEquipCardError)), session)
			return
		}
		//添加武器牌
		user.SiteCards[req.JustCardKey].Arms = user.HandCards[req.CardKey]
		user.SiteCards[req.JustCardKey].AdditionalAttack += user.HandCards[req.CardKey].Attack
		user.SiteCards[req.JustCardKey].TotalAttack += user.HandCards[req.CardKey].Attack
		user.HandCards = append(user.HandCards[:req.CardKey], user.HandCards[req.CardKey+1:]...)
	} else {
		g.sendDataUsers([]string{uidStr}, GameErrorResponseData(common.F(biz.GameOperateError)), session)
		return
	}
	g.sendDataUsers([]string{uidStr}, GameSendHandCardsPushData(user.HandCards), session)
	g.sendDataUsers([]string{uidStr}, GameSendSiteCardsPushData(user.SiteCards), session)
	g.gameData.Users[chairID] = user

}

// battleHandle 对战处理
func (g *GameFrame) battleHandle(layout *[]BattleLayout) {
	//游戏状态 对战 推送
	g.gameData.GameStatus = Battle
	logs.Warn("房间%v,现在是对战开始,状态为%d", g.r.GetRoomID(), g.gameData.GameStatus)
	g.sendData(GameStatusPushData(g.gameData.GameStatus, g.gameRule.OperateSleep, 0))
	ticker := time.NewTicker(3 * time.Second)
	defer ticker.Stop()
	for range ticker.C {
		//没m执行3组的数据打斗
		endFor := g.battleManager(layout)
		//循环结束
		if endFor {
			break
		}
	}
	//对局结束
	if g.gameInCount(0) < 2 { //结算
		g.gameData.GameStatus = Result
		//结束游戏
		g.ch <- ChHandler{GameStatus: Result}
	} else { //重新选牌
		g.ch <- ChHandler{GameStatus: Select}
		//g.sendHandle()
	}
}

// battleManager 对战详细处理
func (g *GameFrame) battleManager(data *[]BattleLayout) bool {
	endFor := true
	battle := *data
	for k, v := range battle {
		//oneUidStr := []string{fmt.Sprintf("%d", v.One.UID)}
		//twoUidStr := []string{fmt.Sprintf("%d", v.Two.UID)}
		oneChairID := v.One.ChairID
		twoChairID := v.Two.ChairID
		if v.Status {
			battle[k] = g.battleBalance(v)
			continue
		}
		endFor = false
		oneLen := len(v.One.Monsters)
		twoLen := len(v.Two.Monsters)
		if oneLen <= 0 && twoLen <= 0 { //两方都没有怪兽卡了 平局
			v.One.Status = 2
			v.Two.Status = 2
			v.Status = true
			// 本人等级 * 回合数 * 掉血倍数
			v.One.BloodLoss = int64(g.gameData.CurBureau)
			v.Two.BloodLoss = int64(g.gameData.CurBureau)
			//人物技能
			var oneSkillVal, twoSkillVal int64
			if g.gameData.Users[v.One.ChairID].IsSkill && g.gameData.Users[v.One.ChairID].SkillType == DamageSubOrAdd {
				oneSkillVal = g.getUserByChairID(v.One.ChairID).UserInfo.RoleSkillVal
				g.sendDataUsersInt([]int{oneChairID}, GameSkillPushData(2, g.getUserByChairID(v.One.ChairID).UserInfo.RoleSkillDesc))
			}
			if g.gameData.Users[v.Two.ChairID].IsSkill && g.gameData.Users[v.Two.ChairID].SkillType == DamageSubOrAdd {
				oneSkillVal = g.getUserByChairID(v.Two.ChairID).UserInfo.RoleSkillVal
				g.sendDataUsersInt([]int{twoChairID}, GameSkillPushData(2, g.getUserByChairID(v.Two.ChairID).UserInfo.RoleSkillDesc))
			}
			if oneSkillVal > 0 {
				v.Two.BloodLoss += oneSkillVal
			} else {
				v.One.BloodLoss += oneSkillVal
			}
			if twoSkillVal > 0 {
				v.One.BloodLoss += twoSkillVal
			} else {
				v.Two.BloodLoss += twoSkillVal
			}
		} else if oneLen <= 0 { //two win
			v.One.Status = -1
			v.Two.Status = 1
			v.Status = true
			// 对方剩余的卡牌数 * 本人等级 * 回合数 * 掉血倍数
			v.One.BloodLoss = int64(twoLen)*g.gameRule.BloodLossSub + int64(g.gameData.CurBureau-1)
			//人物技能
			var oneSkillVal, twoSkillVal int64
			if g.gameData.Users[v.One.ChairID].IsSkill && g.gameData.Users[v.One.ChairID].SkillType == DamageSubOrAdd {
				oneSkillVal = g.getUserByChairID(v.One.ChairID).UserInfo.RoleSkillVal
				g.sendDataUsersInt([]int{oneChairID}, GameSkillPushData(2, g.getUserByChairID(v.One.ChairID).UserInfo.RoleSkillDesc))
			}
			if g.gameData.Users[v.Two.ChairID].IsSkill && g.gameData.Users[v.Two.ChairID].SkillType == DamageSubOrAdd {
				oneSkillVal = g.getUserByChairID(v.Two.ChairID).UserInfo.RoleSkillVal
				g.sendDataUsersInt([]int{twoChairID}, GameSkillPushData(2, g.getUserByChairID(v.Two.ChairID).UserInfo.RoleSkillDesc))
			}
			if oneSkillVal < 0 {
				v.One.BloodLoss += oneSkillVal
			}
			if twoSkillVal > 0 {
				v.One.BloodLoss += twoSkillVal
			}
		} else if twoLen <= 0 { //one win
			v.One.Status = 1
			v.Two.Status = -1
			v.Status = true
			// 对方剩余的卡牌数 * 本人等级 * 回合数 * 掉血倍数
			v.Two.BloodLoss = int64(oneLen)*g.gameRule.BloodLossSub + int64(g.gameData.CurBureau-1)
			//人物技能
			var oneSkillVal, twoSkillVal int64
			if g.gameData.Users[v.One.ChairID].IsSkill && g.gameData.Users[v.One.ChairID].SkillType == DamageSubOrAdd {
				oneSkillVal = g.getUserByChairID(v.One.ChairID).UserInfo.RoleSkillVal
				g.sendDataUsersInt([]int{oneChairID}, GameSkillPushData(2, g.getUserByChairID(v.One.ChairID).UserInfo.RoleSkillDesc))
			}
			if g.gameData.Users[v.Two.ChairID].IsSkill && g.gameData.Users[v.Two.ChairID].SkillType == DamageSubOrAdd {
				oneSkillVal = g.getUserByChairID(v.Two.ChairID).UserInfo.RoleSkillVal
				g.sendDataUsersInt([]int{twoChairID}, GameSkillPushData(2, g.getUserByChairID(v.Two.ChairID).UserInfo.RoleSkillDesc))
			}
			if oneSkillVal > 0 {
				v.Two.BloodLoss += oneSkillVal
			}
			if twoSkillVal < 0 {
				v.Two.BloodLoss += twoSkillVal
			}
		} else {
			if oneLen <= v.One.Index {
				v.One.Index = 0
			}
			if twoLen <= v.Two.Index {
				v.Two.Index = 0
			}
			oneVal := v.One.Monsters[v.One.Index].Card
			twoVal := v.Two.Monsters[v.Two.Index].Card
			var oneBlood, twoBlood int64

			if oneVal.TotalAttack >= twoVal.SurplusBlood {
				//one的攻击力大于two的血量 移除two的怪兽
				twoBlood = twoVal.SurplusBlood
				twoVal.SurplusBlood = 0
			} else {
				//one的攻击力小于two的血量 扣除血量
				twoBlood = oneVal.TotalAttack
				twoVal.SurplusBlood -= oneVal.TotalAttack
			}
			if twoVal.TotalAttack >= oneVal.SurplusBlood {
				//two的攻击力大于one的血量 移除one的怪兽
				oneBlood = oneVal.SurplusBlood
				oneVal.SurplusBlood = 0
			} else {
				//two的攻击力小于one的血量 扣除血量
				oneBlood = twoVal.TotalAttack
				oneVal.SurplusBlood -= twoVal.TotalAttack
			}
			v.One.Monsters[v.One.Index].Card = oneVal
			v.Two.Monsters[v.Two.Index].Card = twoVal
			oneKey, twoKey := v.One.Index, v.Two.Index
			if oneVal.SurplusBlood <= 0 {
				v.One.Monsters = append(v.One.Monsters[:v.One.Index], v.One.Monsters[v.One.Index+1:]...)
				v.One.Index--
			}
			if twoVal.SurplusBlood <= 0 {
				v.Two.Monsters = append(v.Two.Monsters[:v.Two.Index], v.Two.Monsters[v.Two.Index+1:]...)
				v.Two.Index--
			}
			g.sendDataUsersInt([]int{oneChairID}, GameBattleSiteCardsPushData(oneKey, twoKey, oneBlood, twoBlood, v.One.Monsters, v.Two.Monsters))
			g.sendDataUsersInt([]int{twoChairID}, GameBattleSiteCardsPushData(twoKey, oneKey, twoBlood, oneBlood, v.Two.Monsters, v.One.Monsters))
		}
		v.One.Index++
		v.Two.Index++
		battle[k] = v
	}
	return endFor
}

// battleBalance 对战结束 扣除血量
func (g *GameFrame) battleBalance(layout BattleLayout) BattleLayout {
	if layout.IsHandle {
		return layout
	}
	layout.IsHandle = true
	if layout.One.BloodLoss > 0 {
		g.userBloodLoss(layout.One.ChairID, layout.One.UID, layout.One.BloodLoss)
	}
	if layout.Two.BloodLoss > 0 {
		g.userBloodLoss(layout.Two.ChairID, layout.Two.UID, layout.Two.BloodLoss)
	}
	if layout.One.UID != 0 {
		g.gameData.Users[layout.One.ChairID].Opponent = -2
		g.gameData.Users[layout.One.ChairID].Battle = append(g.gameData.Users[layout.One.ChairID].Battle, layout)
		g.sendDataUsersInt([]int{layout.One.ChairID}, GameMyUserPushData(g.gameData.Users[layout.One.ChairID]))
	}
	if layout.Two.UID != 0 {
		a := BattleLayout{
			One:    layout.Two,
			Two:    layout.One,
			Status: layout.Status,
		}
		g.gameData.Users[layout.Two.ChairID].Opponent = -2
		g.gameData.Users[layout.Two.ChairID].Battle = append(g.gameData.Users[layout.Two.ChairID].Battle, a)
		g.sendDataUsersInt([]int{layout.Two.ChairID}, GameMyUserPushData(g.gameData.Users[layout.Two.ChairID]))
	}
	return layout
}

// userBloodLoss 扣除用户血量
func (g *GameFrame) userBloodLoss(chairID int, uid uint, loss int64) {
	user := g.gameData.Users[chairID]
	//uidStr := []string{fmt.Sprintf("%d", uid)}
	if user.UID != uid {
		g.sendDataUsersInt([]int{user.ChairID}, GameErrorResponseData(common.F(biz.GameOperateError)))
		return
	}
	blood := loss
	if user.Blood < loss {
		blood = user.Blood
	}
	//扣除血量
	user.Blood -= blood
	g.sendDataUsersInt([]int{user.ChairID}, GameBloodPushData(-loss, user.Blood))
	if user.Blood <= 0 {
		user.Ranking = g.gameInCount(0)
		user.Status = UserStatusEnd
		user.IsSkill = true
		g.sendDataUsersInt([]int{user.ChairID}, GameStatusPushData(Result, g.gameRule.OperateSleep, user.Ranking))
		g.getUserByChairID(chairID).UserStatus = proto.Dismiss
		// TODO 把卡牌退回牌组
		g.logic.retreatHandCards(g.gameData.Users[chairID].HandCards)
		g.logic.retreatSiteCards(g.gameData.Users[chairID].SiteCards)
		timer, ok := g.usersHeartbeat[g.gameData.Users[chairID].UID]
		g.logic.End(user.UID, g.r.GetRoomID())
		if ok {
			timer.Stop()
			delete(g.usersHeartbeat, uid)
		}
		//for k := range g.gameData.Users[chairID].HandCards {
		//	//退还手牌
		//	g.logic.retreatHandCards(g.gameData.Users[chairID].HandCards[k])
		//	//删除手牌
		//	g.gameData.Users[chairID].HandCards = append(g.gameData.Users[chairID].HandCards[:k], g.gameData.Users[chairID].HandCards[k+1:]...)
		//}
		//for k := range g.gameData.Users[chairID].SiteCards {
		//	//退还场地牌
		//	g.logic.retreatSiteCards(g.gameData.Users[chairID].SiteCards[k])
		//	//删除场地牌
		//	g.gameData.Users[chairID].SiteCards = append(g.gameData.Users[chairID].SiteCards[:k], g.gameData.Users[chairID].SiteCards[k+1:]...)
		//}
	}
	//对战对手改为无对战
	//user.Opponent = -2
	g.gameData.Users[chairID] = user
}

// endGame 游戏结束
func (g *GameFrame) endGame() {
	//marshal, err := json.Marshal(&g.gameData.Users)
	logs.Warn("房间%v,现在是游戏结算,状态为%d", g.r.GetRoomID(), g.gameData.GameStatus)
	for k, v := range g.gameData.Users {
		if v.Status != UserStatusEnd {
			g.gameData.Users[k].Ranking = g.gameInCount(0)
			g.gameData.Users[k].Status = UserStatusEnd
			g.gameData.Users[k].IsSkill = true
			g.getUserByChairID(k).UserStatus = proto.Dismiss
			//uidStr := []string{fmt.Sprintf("%d", v.UID)}
			g.sendDataUsersInt([]int{v.ChairID}, GameStatusPushData(Result, g.gameRule.OperateSleep, g.gameData.Users[k].Ranking))
			timer, ok := g.usersHeartbeat[g.gameData.Users[k].UID]
			if ok {
				timer.Stop()
				delete(g.usersHeartbeat, g.gameData.Users[k].UID)
			}
		}
	}
	//结算
	users := g.endUsers()
	g.logic.EndGame(&users, g.r.GetRoomID(), g.gameRule.BaseScore*int64(g.gameRule.MaxPlayerCount), g.gameRule.MaxPlayerCount, g.gameRule.ChampionRate, g.gameRule.RunnerRate, g.gameRule.ThirdPlaceRate)
	//解散房间
	g.r.DismissRoom()
}

// endUsers 结算用户数据组装
func (g *GameFrame) endUsers() []EndGameUsers {
	var users []EndGameUsers
	for _, v := range g.gameData.Users {
		users = append(users, EndGameUsers{
			UID:       v.UID,
			Blood:     v.Blood,
			Level:     v.Level,
			Ranking:   v.Ranking,
			ChairID:   v.ChairID,
			IsSkill:   v.IsSkill,
			SkillType: v.SkillType,
			HandCards: v.HandCards,
			SiteCards: v.SiteCards,
			Battle:    v.Battle,
			IsHangUp:  v.IsHangUp,
		})
	}
	return users
}

// initUser 初始化用户数据
func (g *GameFrame) initUser(chairID int, session *remote.Session) Users {
	var nextLevelGold = (g.gameRule.InitLevel + 1) * g.gameRule.EachLevelGoldRate
	siteCards := make([]MonstersCard, 0)
	for k := range siteCards {
		siteCards[k].UpCard = make([]Card, 0)
		siteCards[k].Evolution.UpCard = make([]Card, 0)
	}
	var skillRefreshVal int64
	//if SkillType(g.getUserByChairID(chairID).UserInfo.RoleSkillType) == Refresh {
	//	skillRefreshVal = g.getUserByChairID(chairID).UserInfo.RoleSkillVal
	//}
	skillRefreshVal = g.getUserByChairID(chairID).UserInfo.RoleSkillVal
	userInfo := g.getUserByChairID(chairID)
	user := Users{
		UID:                userInfo.UserInfo.UID,
		ChairID:            chairID,
		Opponent:           -2,
		Blood:              g.gameRule.InitBlood,
		Level:              g.gameRule.InitLevel,
		Gold:               g.gameRule.InitGold,
		NextLevelGold:      nextLevelGold,
		NextLevelGoldTotal: nextLevelGold,
		Refresh:            make([]RefreshCard, 0),
		HandCards:          make([]Card, 0),
		SiteCards:          siteCards,
		SkillType:          SkillType(g.getUserByChairID(chairID).UserInfo.RoleSkillType),
		SkillPrice:         g.getUserByChairID(chairID).UserInfo.RoleSkillPrice,
		SkillRefreshVal:    skillRefreshVal,
		IsSkill:            false,
		Status:             UserStatusIn,
		Battle:             make([]BattleLayout, 0),
		Session:            userInfo.Session,
	}
	go g.checkUserHeartbeatTimer(chairID, userInfo.UserInfo.UID, userInfo.Session)
	return user
}

// checkUserHeartbeatTimer 用户心跳检测
func (g *GameFrame) checkUserHeartbeatTimer(chairID int, uid uint, session *remote.Session) {
	g.Lock()
	defer g.Unlock()
	timer, ok := g.usersHeartbeat[uid]
	if ok {
		timer.Stop()
	}
	g.usersHeartbeat[uid] = time.AfterFunc(time.Duration(UserWebTime)*time.Second, func() {
		timer, ok = g.usersHeartbeat[uid]
		if ok {
			timer.Stop()
			delete(g.usersHeartbeat, uid)
		}
		//长时间未操作挂机，强制结束本剧游戏
		//for k := range g.battleUsers {
		//	if k == chairID {
		//		g.battleUsers = append(g.battleUsers[:k], g.battleUsers[k+1:]...)
		//	}
		//}
		user := g.gameData.Users[chairID]
		logs.Warn("检测到用户%d挂机", user.UID)
		//user.Ranking = g.gameInCount(0)
		//user.Status = UserStatusEnd
		//g.logic.End(user.UID, g.r.GetRoomID())
		//user.IsSkill = true
		user.IsHangUp = true
		g.getUserByChairID(chairID).UserStatus = proto.Dismiss
		g.sendDataUsersInt([]int{chairID}, GameOutPushData())
		g.gameData.Users[chairID] = user
	})
}

func (g *GameFrame) run() {
OuterLoop:
	for {
		select {
		case data := <-g.ch:
			switch data.GameStatus {
			case Select:
				go g.sendHandle()
				break
			case Playing:
				go g.distributionBattle()
				break
			case Battle:
				go g.battleHandle(data.Battle)
				break
			case Result:
				go g.endGame()
				break OuterLoop
			}
			break
		}
	}
}

func NewGameFrame(rule request.GameRule, r base.RoomFrame, gameService *service.GameService) *GameFrame {
	gameData := initGameData(rule)
	g := &GameFrame{
		r:              r,
		gameRule:       rule,
		gameData:       gameData,
		logic:          NewLogic(gameService, rule.GameType),
		usersHeartbeat: make(map[uint]*time.Timer),
		ch:             make(chan ChHandler, 1024),
		battleUsers:    make([]int, 0),
	}
	go g.run()
	return g
}

func initGameData(rule request.GameRule) *GameData {
	g := new(GameData)
	g.ChairCount = rule.MaxPlayerCount
	g.GameStatus = GameStatusNone
	g.Users = make([]Users, g.ChairCount)
	return g
}
